package com.atguigu.gulimail.product.service.impl;

import com.atguigu.common.To.SkuReductionTo;
import com.atguigu.common.To.SpuBoundTo;
import com.atguigu.common.constant.ProductConstant;
import com.atguigu.common.es.SkuEsModel;
import com.atguigu.common.utils.R;
import com.atguigu.gulimail.product.Feign.CouponFeignService;
import com.atguigu.gulimail.product.Feign.SearchFeignService;
import com.atguigu.gulimail.product.Feign.WareFeignService;
import com.atguigu.gulimail.product.dao.SpuInfoDescDao;
import com.atguigu.gulimail.product.entity.*;
import com.atguigu.gulimail.product.service.*;
import com.atguigu.gulimail.product.vo.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;

import com.atguigu.gulimail.product.dao.SpuInfoDao;
import org.springframework.transaction.annotation.Transactional;


@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

    @Autowired
    SpuInfoDescService descService;
    @Autowired
    SpuImagesService imagesService;
    @Autowired
    AttrService attrService;
    @Autowired
    ProductAttrValueService valueService;
    @Autowired
    SkuImagesService skuImagesService;
    @Autowired
    SkuInfoService skuInfoService;
    @Autowired
    SkuSaleAttrValueService skuSaleAttrValueService;
    @Autowired
    CouponFeignService couponFeignService;
    @Autowired
    BrandService brandService;
    @Autowired
    CategoryService categoryService;
    @Autowired
    ProductAttrValueService attrValueService;
    @Autowired
    WareFeignService wareFeignService;
    @Autowired
    SearchFeignService searchFeignService;
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                new QueryWrapper<SpuInfoEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * TODO 高级部分优化问题
     * @param vo
     */
    @Override
    @Transactional
    public void saveSpuVo(SpuSaveVo vo) {
        //1.保存 spu 基本属性 spu_info(spu_name,spu_description,catalog_id,brand_id,weight,publish_status)
        SpuInfoEntity spuInfo = new SpuInfoEntity();
        BeanUtils.copyProperties(vo,spuInfo);
        spuInfo.setCreateTime(new Date());
        spuInfo.setUpdateTime(new Date());
        this.saveBaseInfo(spuInfo);


        //2.保存spu的描述图片 spu_info_desc (spuId,desc)
        List<String> decript = vo.getDecript();
        SpuInfoDescEntity spuInfoDesc = new SpuInfoDescEntity();
        spuInfoDesc.setSpuId(spuInfo.getId());
        spuInfoDesc.setDecript(String.join(",",vo.getDecript()));
        descService.saveSpuInfoDesc(spuInfoDesc);


        //3.保存spu的图片集 spu_images (spuID,Url)
        imagesService.saveImages(spuInfo.getId(),vo.getImages());

        //4.保存spu的规格参数; pms_product_attr_value
        List<BaseAttrs> baseAttrs=vo.getBaseAttrs();
        List<ProductAttrValueEntity> collect = baseAttrs.stream().map(i -> {
            ProductAttrValueEntity value = new ProductAttrValueEntity();
            value.setAttrId(i.getAttrId());
            value.setSpuId(spuInfo.getId());
            AttrEntity attr = attrService.getById(i.getAttrId());
            value.setAttrName(attr.getAttrName());
            value.setAttrValue(i.getAttrValues());
            value.setQuickShow(i.getShowDesc());

            return value;
        }).collect(Collectors.toList());
        valueService.saveProductAttrValue(collect);

        //保存spu 的积分信息
        //5.5> spu的积分信息
        SpuBoundTo spuBoundTo = new SpuBoundTo();
        Bounds bounds = vo.getBounds();
        BeanUtils.copyProperties(bounds,spuBoundTo);
        spuBoundTo.setSpuId(spuInfo.getId());

        R r2=couponFeignService.saveSpuBounds(spuBoundTo);
        if (r2.getCode()!=0){
            log.error("远程保存Spu积分信息失败!!!!");
        }


        //5.保存当前的spu对应的所有sku信息
        //5.1> sku的基本信息: sku_info
        List<Skus> skuses=vo.getSkus();
        if (skuses!=null|skuses.size()>0){
            skuses.forEach(item->{
                String defaultImage="";
                for (Images image:item.getImages()) {
                    if(image.getDefaultImg()==1){
                        defaultImage=image.getImgUrl();
                    }
                }
                
                SkuInfoEntity skuInfo=new SkuInfoEntity();
                skuInfo.setSpuId(spuInfo.getId());
                skuInfo.setCatalogId(spuInfo.getCatalogId());
                skuInfo.setBrandId(spuInfo.getBrandId());
                skuInfo.setSaleCount(0L);
                skuInfo.setSkuDefaultImg(defaultImage);
                BeanUtils.copyProperties(item,skuInfo);

                skuInfoService.saveSkuInfo(skuInfo);
                System.out.println(skuInfo);
                //5.2> sku的图片信息: sku_images
                Long skuId=skuInfo.getSkuId();

                List<SkuImagesEntity> SkuImagesList = item.getImages().stream().map(images -> {
                    SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
                    skuImagesEntity.setSkuId(skuId);
                    skuImagesEntity.setImgUrl(images.getImgUrl());
                    skuImagesEntity.setDefaultImg(images.getDefaultImg());
                    return skuImagesEntity;
                }).filter(entity->{
                    return StringUtils.isNotEmpty(entity.getImgUrl());
                }).collect(Collectors.toList());
                skuImagesService.saveBatch(SkuImagesList);

                //5.3> sku的销售属性信息: sku_sale_attr_value
                List<Attr> attrs=item.getAttr();
                List<SkuSaleAttrValueEntity> attrValueEntities = attrs.stream().map(attr -> {
                    SkuSaleAttrValueEntity attrValueEntity = new SkuSaleAttrValueEntity();
                    BeanUtils.copyProperties(attr, attrValueEntity);
                    attrValueEntity.setSkuId(skuId);
                    return attrValueEntity;
                }).collect(Collectors.toList());
                skuSaleAttrValueService.saveBatch(attrValueEntities);

                //5.4> sku的优惠,满减信息 gulimail_sms
                SkuReductionTo skuReductionTo=new SkuReductionTo();
                BeanUtils.copyProperties(item,skuReductionTo);
                skuReductionTo.setSkuId(skuId);
                if(skuReductionTo.getFullCount()>0||skuReductionTo.getFullPrice().compareTo(BigDecimal.valueOf(0))==1){
                    R r1=couponFeignService.saveSkuReduction(skuReductionTo);
                    if (r1.getCode()!=0){
                        log.error("远程保存Spu优惠信息失败!!!!");
                    }

                }

            });

        }
    }

    @Override
    public void saveBaseInfo(SpuInfoEntity entity) {
        this.baseMapper.insert(entity);
    }

    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {

        LambdaQueryWrapper<SpuInfoEntity> key =new LambdaQueryWrapper<>();
        key.eq(StringUtils.isNotEmpty((String) params.get("brandId")),SpuInfoEntity::getBrandId,params.get("brandId"))
                .eq(StringUtils.isNotEmpty((String)params.get("catelogId")),SpuInfoEntity::getCatalogId, params.get("catelogId"))
                .like(StringUtils.isNotEmpty((String)params.get("key")),SpuInfoEntity::getSpuName, params.get("key"))
                .eq(StringUtils.isNotEmpty((String)params.get("status")),SpuInfoEntity::getPublishStatus, params.get("status"));


        IPage<SpuInfoEntity> page=this.page(
                new Query<SpuInfoEntity>().getPage(params),key
        );
        return new PageUtils(page);
    }

    @Override
    @Transactional
    public void up(Long spuId) {
        List<SkuEsModel> upProducts = new ArrayList<>();
        //1.组装需要的数据

        //1.1 查询spu的所有sku
        List<SkuInfoEntity> bySpuId = skuInfoService.getBySpuId(spuId);
        //聚合sku的Id
        List<Long> skuIds = bySpuId.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());
        R r = null;
        if (!bySpuId.isEmpty()) {
            //TODO 1.2 查询当前sku的所有可以被用来检索的规格属性
            LambdaQueryWrapper<ProductAttrValueEntity> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(ProductAttrValueEntity::getSpuId, spuId);
            //首先查到spu对应所有的attr
            List<ProductAttrValueEntity> productAttrValueEntities = attrValueService.list(wrapper);
            //然后查询pms_attr表可以被检索的attr数据
            LambdaQueryWrapper<AttrEntity> attrEntityLambdaQueryWrapper = new LambdaQueryWrapper<>();
            attrEntityLambdaQueryWrapper.eq(AttrEntity::getSearchType, 1);
            List<AttrEntity> attrEntityList = attrService.list(attrEntityLambdaQueryWrapper);

            //然后筛选出所有可检索的spu对应的attr信息
            //然后将筛选出来的attr信息封装成SkuEsModel里面的attr数据
            List<Long> collectId = attrEntityList.stream().map(AttrEntity::getAttrId).collect(Collectors.toList());
            List<SkuEsModel.Attrs> attrsModel = productAttrValueEntities.stream()
                    .filter(i -> collectId.contains(i.getAttrId()))
                    .map(i -> {
                        SkuEsModel.Attrs attrs = new SkuEsModel.Attrs();
                        BeanUtils.copyProperties(i, attrs);
                        return attrs;
                    })
                    .collect(Collectors.toList());

            //TODO  发送远程调用查看是否有库存
            Map<Long, Boolean> skuHasStockMap = null;
            try {
                List<SkuStock> skuHasStock = wareFeignService.getSkuHasStock(skuIds);
                skuHasStockMap = skuHasStock.stream().collect(Collectors.toMap(SkuStock::getSkuId, SkuStock::getStock));

            } catch (Exception e) {
                log.error("库存调用出现异常:{}！！", e);
            }
            //TODO 查询品牌和分类的名字
            BrandEntity brand = brandService.getById(bySpuId.get(0).getBrandId());
            CategoryEntity category = categoryService.getById(bySpuId.get(0).getCatalogId());
            Map<Long, Boolean> finalSkuHasStockMap = skuHasStockMap;
            List<SkuEsModel> esModelList = bySpuId.stream().map(item -> {
                SkuEsModel esModel = new SkuEsModel();
                BeanUtils.copyProperties(item, esModel);
                esModel.setBrandImg(item.getSkuDefaultImg());
                esModel.setSkuPrice(item.getPrice());
                //设置是否有库存
                if (finalSkuHasStockMap == null) {
                    esModel.setHasStock(true);  //库存调用异常默认设置为有库存
                } else {
                    esModel.setHasStock(finalSkuHasStockMap.get(item.getSkuId()));
                }
                //TODO 热度评分
                esModel.setHotScore(0L);
                esModel.setCatalogName(category.getName());
                esModel.setBrandName(brand.getName());
                //设置检索属性
                esModel.setAttrs(attrsModel);
                return esModel;
            }).collect(Collectors.toList());

            //TODO 将数据保存在Es中
            r = searchFeignService.productStatusUp(esModelList);

        }

        if (r == null || r.getCode() == 0) {
            //远程调用成功
            //TODO 修改状态为已上架
            baseMapper.updateSpuStatus(spuId, ProductConstant.StatusEnum.SPU_UP.getCode());
        }else {
            //远程调用失败
            //TODO 重复调用？接口幂等性
            /**frign的调用流程
             1. 构造请求数据,将对象转为json
             2. 发送请求进行执行(执行成功会解码响应数据)
             3. 执行请求会有重试机制
             while(true){ }

             */
        }
    }

    @Override
    public SpuInfoEntity getBySkuId(Long skuId) {

        SkuInfoEntity skuInfo = skuInfoService.getById(skuId);
        Long spuId=skuInfo.getSpuId();
        SpuInfoEntity spu = this.getById(spuId);
        return spu;
    }


}